/*
 *	CODESPACE ++
 *	A real-time syntax highlighting javascript editor
 *
 *	Copyright (C) 2008 Francois Botman, <Franchie.brightspark@gmail.com>
 *
 *	This script is licenced under: Creative Commons Attribution-Noncommercial-Share Alike 3.0
 *	(see http://creativecommons.org/licenses/by-nc-sa/3.0/).
 *	It bascially means that it can be modified and shared, provided it is
 *	clearly attributed, and can be used in personnal/charity projects for free!
 *	(Commercial use requires prior negotiation with the author).
 *	In any case, should anything go wrong, I cannot be held responsible!
 *
 *	Based on an original idea by Fernando M.A.d.S.,  http://codepress.org/
 *
 *	-----------
 *
 *	This file contains the Caret object that contains all the information about a caret.
 *	This file only handles:
 *		- curson display/update
 *		- selection overlay
 *		- selection erasure procedures
 */

Codespace.Caret = function(editor)
{
	this.objOffset = 0;
	this.obj = null;
	var self_caret = this;
	
	// This moves the 'caret' to a specified line (1-based) and position (0-based). The given positions are assumed valid.
	// If pos<0, it is moved to the end of the line!
	this.move = function(line, pos) {
		if(line >= editor.table.rows.length) line = editor.table.rows.length-1;
		var w = editor.table.rows[line].lineobj.words;
		var l = w.length;
		var i = 0;
		
		while(i<l && (pos < 0 || pos > (w[i].text ? w[i].text.length : 0))) {
			pos -= (w[i].text ? w[i].text.length : 0);
			self_caret.obj = w[i];
			i++;
		}
		if(!self_caret.obj) self_caret.obj = w[0];
		self_caret.objOffset = ((self_caret.obj && self_caret.obj.text && (pos<0 || pos>self_caret.obj.text.length)) ? self_caret.obj.text.length : pos);
	}
	
	// Helper function: returns the next word's object.
	function getNextWord(obj) {
		/*if(obj.nextSibling) return obj.nextSibling;
		if(obj.lineobj.next) return obj.lineobj.next.words[0];*/
		var w = obj.lineobj.words;
		var i = w.indexOf(obj)+1;
		if(i<w.length) return w[i];
		if(obj.lineobj.next) return obj.lineobj.next.words[0];
		return null;
	}
	editor.getNextWord = getNextWord;
	function getPrevWord(obj) {
		/*if(obj.previousSibling) return obj.previousSibling;
		if(obj.lineobj.prev) return obj.lineobj.prev.words[ obj.lineobj.prev.words.length - 1];*/
		var w = obj.lineobj.words;
		var i = w.indexOf(obj)-1;
		if(i>-1) return w[i];
		if(obj.lineobj.prev) return obj.lineobj.prev.words[ obj.lineobj.prev.words.length - 1 ];
		return null;
	}
	editor.getPrevWord = getPrevWord;
	
	/*
	 *	This moves the cursor by a relative position.
	 *	It also caters for the following cases:
	 *		- start/end of text: just stops.
	 *		- start/end of line: extra arrow movement needed to go down a line.
	 */
	this.moveRelative = function(rpos) {
		var obj = self_caret.obj;
		while(rpos > 0) {
			if(self_caret.objOffset < (obj.text ? ((obj==obj.lineobj.words[obj.lineobj.words.length-1]) ? (obj.text.length) : (obj.text.length-1)) : 0)) {rpos--;self_caret.objOffset++;}
			else if(obj = getNextWord(obj)) {rpos--;self_caret.obj=obj;self_caret.objOffset=0;}
			else return;
		}
		while(rpos < 0) {
			if(self_caret.objOffset > (obj==obj.lineobj.words[0] ? 0 : 1)) {rpos++;self_caret.objOffset--;}
			else if(obj = getPrevWord(obj)) {rpos++;self_caret.obj=obj;self_caret.objOffset = (obj.text ? obj.text.length : 0);}
			else return;
		}
	}
	
	// This moves the cursor up/down a *displayed* row.
	this.moveDown = function(down) {
		// Get current left edge!
		var left = self_caret.obj.offsetLeft + ((self_caret.obj.text && self_caret.objOffset) ? ((self_caret.obj.offsetWidth * self_caret.objOffset) / self_caret.obj.text.length) : 0);
		var obj = self_caret.obj;
		
		// Actually go down!
		while(down>0) {
			do {
				self_caret.obj = obj;
				obj = getNextWord(obj);
			} while(obj && !(obj.offsetLeft<=left && (obj.offsetLeft+obj.offsetWidth)>left));
			if(obj) {
				self_caret.obj = obj;
				self_caret.objOffset = (obj.text) ? Math.floor( obj.text.length * (left-obj.offsetLeft)/obj.offsetWidth) : 0;
			}
			else return (self_caret.objOffset = (self_caret.obj.text ? self_caret.obj.text.length : 0));
			down --;
		}
		
		// Go up!
		while(down<0) {
			do {
				self_caret.obj = obj;
				obj = getPrevWord(obj);
			} while(obj && !(obj.offsetLeft<=left && (obj.offsetLeft+obj.offsetWidth)>left));
			if(obj) {
				self_caret.obj = obj;
				self_caret.objOffset = Math.floor( obj.text.length * (left-obj.offsetLeft)/obj.offsetWidth);
			}
			else return (self_caret.objOffset = 0);
			down ++;
		}
	}
}